package com.wangshb.upms.core.spring.security;

import com.wangshb.upms.core.utils.JwtTokenUtils;
import com.wangshb.upms.core.utils.SecurityUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.parameters.P;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 * 定义tokenId的过滤器
 *
 * 如果请求头中存在tokenId, 则根据tokenId获取已经登陆的信息
 */
@Slf4j
public class JwtAuthenticationTokenFilter extends BasicAuthenticationFilter {

    private RequestHeaderRequestMatcher requiresAuthenticationRequestMatcher;


    public JwtAuthenticationTokenFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);

        //拦截header中带Authorization的请求
        this.requiresAuthenticationRequestMatcher = new RequestHeaderRequestMatcher("Authorization");
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        //header没带token的，直接放过，因为部分url匿名用户也可以访问
        //如果需要不支持匿名用户的请求没带token，这里放过也没问题，因为SecurityContext中没有认证信息，后面会被权限控制模块拦截
        if (!requiresAuthentication(request, response)) {
            filterChain.doFilter(request, response);
            return;
        }

        Authentication authResult = null;

        // 根据token获取用户信息
        try {
            String token = JwtTokenUtils.getToken(request);

            if (StringUtils.isNotBlank(token)) {
                authResult = this.getAuthenticationManager().authenticate(new JwtAuthenticatioToken(token));
            }

        } catch (AuthenticationException e) {
            unsuccessfulAuthentication(request, response, e);
        }

        if (null != authResult) {
            successfulAuthentication(request, response, filterChain, authResult);
        }

        filterChain.doFilter(request, response);
    }

    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {

        // 存储登录认证信息到上下文
        SecurityContextHolder.getContext().setAuthentication(authResult);

        // 校验token是否即将过期
        // 生成并返回token给客户端，后续访问携带此token
        String token = ((JwtAuthenticatioToken) authResult).getToken();
        if (JwtTokenUtils.shouldRefreshToken(token)){
            String newToken = JwtTokenUtils.refreshToken(token);
            response.setHeader("Authentication", newToken);
        }
    }


    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        log.info("token 验证失败 : " + failed.getMessage(), failed);
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
    }




    protected boolean requiresAuthentication(HttpServletRequest request,
                                             HttpServletResponse response) {
        return requiresAuthenticationRequestMatcher.matches(request);
    }
}
